﻿package  systems.particles 
{
	import color.HSL;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageDisplayState;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.geom.ColorTransform;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	/**
	 * @author Nicolas Barradeau
	 */
	public class Perlin extends Sprite
	{
		//dessin
		private var tmp:BitmapData;
		
		//sortie
		private var output:BitmapData;
		private var bmp:Bitmap;
		
		//remplacer par un Vector.<Particle> si besoin
		private var particles:Vector.<Particle>;
		
		
		//deplacement
		private var map:BitmapData;
		private var buffer:BitmapData;
		private var angle:Number = 0;
		private var bufferRect:Rectangle;
		private var bufferScale:Number = .2;
		private var hue:Number = 0;
		
		
		public function Perlin() 
		{
			
			
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.displayState = StageDisplayState.FULL_SCREEN;
			
			output = new BitmapData( stage.stageWidth, stage.stageWidth, true, 0 );
			bmp = Bitmap( addChild( new Bitmap( output, 'auto', false ) ) );
			
			tmp = output.clone();
			
			particles = new Vector.<Particle>();
			var i:int = 1000;
			while ( --i ) particles.push( new Particle( Math.random() * output.width, Math.random() * output.height, 0xFF << 24 | HSL.getHex( hue += .001, 1, .5 ) ) );
			
			
			//pour le deplacement trop joli
			map = new BitmapData( output.width, output.height, false );
			buffer = new BitmapData( output.width * bufferScale, output.height * bufferScale, false );
			bufferRect = new Rectangle( 0,0, buffer.width, buffer.height );
			map.perlinNoise( 100, 100, 2, 0, true, true, 1 | 2 | 4, false );
			
			//addChild( new Bitmap( buffer ) ); // debug : voir le map de deplacement
			
			addEventListener( Event.ENTER_FRAME, enterFrameHandler );
			
		}
		
		private function enterFrameHandler(e:Event):void 
		{
			
			tmp.fillRect( tmp.rect, 0 );
			
			moveIt();
			
			
			output.draw( tmp );
			//output.colorTransform( output.rect, new ColorTransform( 1, 1, 1, 1, -3, -3, -3, -3 ) );
			output.colorTransform( output.rect, new ColorTransform( 1, 1, 1, .9999 ) );
			
		}
		
		private function moveIt():void
		{
			
			//mouvement
			angle += Math.PI / 180;
			bufferRect.x = output.width / 2 + Math.cos( angle ) * 100;
			bufferRect.y = output.height / 2 + Math.sin( angle ) * 100;
			buffer.copyPixels( map, bufferRect, new Point( 0, 0 ) );
			
			
			var p:Particle;
			//p = new Particle( mouseX, mouseY );
			//p = new Particle( 	mouseX + (Math.random() - .5) * 10, mouseY + (Math.random() - .5) * 10 );
			//p = new Particle( 	mouseX + Math.cos(angle) * 100, mouseY + Math.sin(angle) * 100 );
			var i:int = 10;
			while ( --i )
			{
				p = new Particle(	Math.random() * output.width , Math.random() * output.height );
				p.color = 0xFF << 24 | HSL.getHex( ( hue += .1 ) % 360, 1, .5 ); 
				particles.push( p );
			}
			
			
			var c:int;
			var left:Vector.<Particle> = Vector.<Particle>( [] );
			for each ( p in particles )
			{
				//pioche une couleur sur le map
				c = buffer.getPixel( p.x * bufferScale, p.y  * bufferScale );
				
				//estime le déplacement en X Y en fonction du rouge et du vert
				p.x += (((c >> 16) & 0xff) - 0x80) / 0x80 * 20;
				p.y += (((c >> 8) & 0xff) - 0x80) / 0x80 * 20; 
			
				//si la particule est dans le champ
				if ( output.rect.contains( p.x, p.y ) )
				{
					drawLine( tmp, p.x, p.y, p.ox, p.oy, p.color );
					p.ox = p.x;
					p.oy = p.y;
					left.push( p );
				}
				
			}
			particles = left.concat();
			
		}
		
		// dessine une ligne rasterisée entre 2 points
		public function drawLine( bd:BitmapData, x:int, y:int, x2:int, y2:int, color:uint):void
		{
			//if ( bd == null ) return;
			
			var shortLen:int = y2-y;
			var longLen:int = x2 - x;
			var yLonger:Boolean;
			
			if((shortLen ^ (shortLen >> 31)) - (shortLen >> 31) > (longLen ^ (longLen >> 31)) - (longLen >> 31))
			{
				shortLen ^= longLen;
				longLen ^= shortLen;
				shortLen ^= longLen;
				yLonger = true;
			}
			else
			{
				yLonger = false;
			}
			
			var inc:int = longLen < 0 ? -1 : 1;
			
			var multDiff:Number = longLen == 0 ? shortLen : shortLen / longLen;
			
			if (yLonger) 
			{
				for (var i:int = 0; i != longLen; i += inc) 
				{
					bd.setPixel32(x + i*multDiff, y+i, color);
				}
			} 
			else 
			{
				for (i = 0; i != longLen; i += inc) 
				{
					bd.setPixel32(x + i, y + i * multDiff, color);
				}
			}
		}
		
	}
}
class Particle
{
	
	public var a:int = 0;
	public var s:Number = 0;
	
	
	public var x:int;
	public var ox:int;
	public var y:int;
	public var oy:int;
	
	public var color:uint = 0xFF777777;
	
	public function Particle ( x:int, y:int, color:uint = 0xFFFFFFFF )
	{
		this.x = ox = x;
		this.y = oy = y;
		this.color = color;
	}
}